#include "bsp_flash.h"
#include "spi.h"
#include "bsp_led.h"
#include "bsp_lcd.h"
#include "bsp_sram.h"


static void _flash_wait_busy(void);
static void _flash_write_enable(void);
static void _flash_spliteaddr(uint32_t u32Addr, uint8_t *pu8Addrh, uint8_t *pu8Addrm, uint8_t *pu8Addrl);

static uint8_t _spi_receive_onebyte(void);
static HAL_StatusTypeDef _spi_receive_bytes(uint8_t *pu8Data, uint16_t u16Size);
static HAL_StatusTypeDef _spi_transmit_onebyte(uint8_t u8Data);
static HAL_StatusTypeDef _spi_transmit_bytes(uint8_t *pu8Data, uint16_t u16Size);


static uint8_t _flash_readSR1(void);
//static uint8_t _flash_readSR2(void);


static HAL_StatusTypeDef _spi_transmit_onebyte(uint8_t u8Data)
{
    return HAL_SPI_Transmit(FLASH_HANDLE, &u8Data, 1, MAX_TIME_OUT);
}

static HAL_StatusTypeDef _spi_transmit_bytes(uint8_t *pu8Data, uint16_t u16Size)
{
    return HAL_SPI_Transmit(FLASH_HANDLE, pu8Data, u16Size, MAX_TIME_OUT);
}

static uint8_t _spi_receive_onebyte(void)
{
    uint8_t u8Data = 0;
    HAL_SPI_Receive(FLASH_HANDLE, &u8Data, 1, MAX_TIME_OUT);
    return u8Data;
}

static HAL_StatusTypeDef _spi_receive_bytes(uint8_t *pu8Data, uint16_t u16Size)
{
    return HAL_SPI_Receive(FLASH_HANDLE, pu8Data, u16Size, MAX_TIME_OUT);
}

//根据块编号获取绝对地址
uint32_t _flash_addr_byblock(uint8_t u8Block)
{
    uint32_t u32Addr = u8Block;
    u32Addr <<= 16;
    return u32Addr;
}

//根据扇区编号获取绝对地址
uint32_t _flash_addr_bysector(uint16_t u16Sector)
{
    if(u16Sector > 4095)
    {
        return 0;
    }
    uint32_t u32Addr = u16Sector;
    u32Addr <<= 12;
    return u32Addr;
}

//根据页编号获取绝对地址
uint32_t _flash_addr_bypage(uint16_t u16Page)
{
    uint32_t u32Addr = u16Page;
    u16Page <<= 8;
    return u32Addr;
}

//根据块和扇区编号获取绝对地址
uint32_t _flash_addr_byblocksector(uint8_t u8Block, uint8_t u16Sector)
{
    uint32_t u32Addr = u8Block;
    uint32_t u32Offset = u16Sector;
    if(u16Sector > 15)
    {
        u16Sector = 0;
    }
    u32Addr <<= 16;
    u32Offset <<= 12;
    u32Addr += u32Offset;
    return u32Addr;
}

//根据块和扇区和页编号获取绝对地址
uint32_t _flash_addr_byblocksectorpage(uint8_t u8Block, uint8_t u16Sector, uint8_t u16Page)
{
    uint32_t u32Addr = u8Block;
    uint32_t u32Offset = u16Sector;
    if(u16Sector > 15)
    {
        u16Sector = 0;
    }
    if(u16Page > 15)
    {
        u16Page = 0;
    }
    u32Addr <<= 16;
    u32Offset <<= 12;
    u32Addr += u32Offset;
    u32Offset = u16Page;
    u32Offset <<= 8;
    u32Addr += u32Offset;
    return u32Addr;
}

static void _flash_wait_busy(void)
{
    uint8_t u8SR1 = 0x00;
    u8SR1 = _flash_readSR1();
    while((u8SR1 & 0x01) == 0x01)
    {
        HAL_Delay(1);
        u8SR1 = _flash_readSR1();
    }
}

static uint8_t _flash_readSR1(void)
{
    uint8_t u8SR1 = 0x00;
    FLASH_CS_CLR;
    _spi_transmit_onebyte(0x05);
    u8SR1 = _spi_receive_onebyte();
    FLASH_CS_SET;
    return u8SR1;
}

// static uint8_t _flash_readSR2(void)
// {
//     uint8_t u8SR2 = 0x00;
//     FLASH_CS_CLR;
//     _spi_transmit_onebyte(0x35);
//     u8SR2 = _spi_receive_onebyte();
//     FLASH_CS_SET;
//     return u8SR2;
// }

static void _flash_write_enable(void)
{
    FLASH_CS_CLR;
    _spi_transmit_onebyte(0x06);
    FLASH_CS_SET;
    _flash_wait_busy();
}


static void _flash_spliteaddr(uint32_t u32Addr, uint8_t *pu8Addrh, uint8_t *pu8Addrm, uint8_t *pu8Addrl)
{
    *pu8Addrh = (u32Addr >> 16);
    u32Addr = u32Addr & 0x0000FFFF;
    *pu8Addrm = (u32Addr >> 8);
    *pu8Addrl = u32Addr & 0x000000FF;
}


void bsp_flash_init(void)
{
    uint16_t Temp = 0xFF;    
    uint8_t u8Temp = 0x90;
    uint8_t i = 0;
    FLASH_CS_CLR;

    HAL_SPI_Transmit(FLASH_HANDLE, &u8Temp, 1, 0xFF);
    u8Temp = 0x00;
    HAL_SPI_Transmit(FLASH_HANDLE, &u8Temp, 1, 0xFF);
    HAL_SPI_Transmit(FLASH_HANDLE, &u8Temp, 1, 0xFF);
    HAL_SPI_Transmit(FLASH_HANDLE, &u8Temp, 1, 0xFF);

    HAL_SPI_Receive(FLASH_HANDLE, &u8Temp, 1, 0xFF);
    Temp = u8Temp;
    Temp <<= 8;
    HAL_SPI_Receive(FLASH_HANDLE, &u8Temp, 1, 0xFF);
    Temp |= u8Temp;
    FLASH_CS_SET;

    if(0xEF17 != Temp)
    {
        bsp_led_on(2);
        printf("[ERROR] FLASH_HANDLE init error\n");
        LCD_ShowString(0,16,200,16,16,"FLASH_HANDLE init failed!",0xFFFF);
        return;
    }
    LCD_ShowString(0,16,304,16,16,"FLASH_HANDLE init success, ID:0xEF17",0xFFFF);

    //读取GBK编码表
    bsp_flash_read(FONT_GBK_INDEX_START, (uint8_t *)(UTF16_GB2312_MEM_START_ADDR), UTF16_GB2312_MEM_SIZE);
    //读取字形库
    for(i = 0; i < GB2312_SHADE_MEM_LOOP_COUNT; i++)
    {
        bsp_flash_read( FONT_GBK_SHADE_START1 + i * GB2312_SHADE_MEM_PER_READ, 
                        (uint8_t *)(GB2312_SHADE_MEM_START_ADDR + i * GB2312_SHADE_MEM_PER_READ), 
                        GB2312_SHADE_MEM_PER_READ);
    }
    bsp_flash_read(     FONT_GBK_SHADE_START1 + i * GB2312_SHADE_MEM_PER_READ, 
                        (uint8_t *)(GB2312_SHADE_MEM_START_ADDR + i * GB2312_SHADE_MEM_PER_READ), 
                        GB2312_SHADE_MEM_LOOP_LEFT);


    memset((uint8_t *)(FONT_SRC_MEM_LEN_START_ADDR),0x00,0x2000);
    return;
}


void bsp_flash_erasesector(uint32_t u32Addr)
{
    uint8_t u8Byte2, u8Byte3, u8Byte4;
    _flash_spliteaddr(u32Addr, &u8Byte2, &u8Byte3, &u8Byte4);
    _flash_write_enable();
    _flash_wait_busy();
    FLASH_CS_CLR;
    _spi_transmit_onebyte(0x20);
    _spi_transmit_onebyte(u8Byte2);
    _spi_transmit_onebyte(u8Byte3);
    _spi_transmit_onebyte(u8Byte4);
    FLASH_CS_SET;
    _flash_wait_busy();
}

//读取数据 (65535Bytes Max)
void bsp_flash_read(uint32_t u32Addr, uint8_t *pu8Buffer, uint16_t u16ByteCount)
{
    uint8_t u8Byte2, u8Byte3, u8Byte4;
    _flash_spliteaddr(u32Addr, &u8Byte2, &u8Byte3, &u8Byte4);
    FLASH_CS_CLR;
    _spi_transmit_onebyte(0x03);
    _spi_transmit_onebyte(u8Byte2);
    _spi_transmit_onebyte(u8Byte3);
    _spi_transmit_onebyte(u8Byte4);
    _spi_receive_bytes(pu8Buffer, u16ByteCount);
    FLASH_CS_SET;
}

//写一个页的数据 (256Bytes Max)
void bsp_flash_write_page(uint32_t u32Addr, uint8_t *pu8Buffer, uint16_t u16ByteCount)
{
    uint8_t u8Byte2, u8Byte3, u8Byte4;
    _flash_spliteaddr(u32Addr, &u8Byte2, &u8Byte3, &u8Byte4);
    _flash_write_enable();
    _flash_wait_busy();
    FLASH_CS_CLR;
    _spi_transmit_onebyte(0x02);
    _spi_transmit_onebyte(u8Byte2);
    _spi_transmit_onebyte(u8Byte3);
    _spi_transmit_onebyte(u8Byte4);
    _spi_transmit_bytes(pu8Buffer, u16ByteCount);
    FLASH_CS_SET;
    _flash_wait_busy();
}

//写一个扇区 (64KBytes Max)
void bsp_flash_write_sector(uint32_t u32Addr, const uint8_t *pu8Buffer, uint32_t u32ByteCount)
{
    uint32_t u32StartAddr = u32Addr;
    uint8_t *pu8Buf = (uint8_t *)pu8Buffer;
    uint16_t u16LeftBytes = u32ByteCount % FLASH_PAGE_SIZE;
    uint16_t u16PageCount = u32ByteCount / FLASH_PAGE_SIZE;
    uint8_t u8SecCount = (u32ByteCount / FLASH_SECTOR_SIZE);
    
    if((u32ByteCount % FLASH_SECTOR_SIZE) > 0)
    {
        u8SecCount ++;
    }

    for(uint8_t i = 0; i < u8SecCount; i++)
    {
        bsp_flash_erasesector(u32StartAddr);
        u32StartAddr += FLASH_SECTOR_SIZE;
    }

    
    for(uint16_t i = 0; i < u16PageCount; i++)
    {
        bsp_flash_write_page(u32Addr, pu8Buf, FLASH_PAGE_SIZE);
        u32Addr += FLASH_PAGE_SIZE;
        pu8Buf += FLASH_PAGE_SIZE;
        
    }

    if( 0 < u16LeftBytes)
    {
        bsp_flash_write_page(u32Addr, pu8Buf, u16LeftBytes);
    }
}
